﻿using System;
using System.Activities;
using System.Activities.Presentation.PropertyEditing;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Discovery;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;
using WFExtended.Activities.Designers;
using WFExtended.Framework.Presentation;
using WFExtended.Framework.ServiceModel;

namespace WFExtended.Activities
{
    /// <summary>
    /// Build a WCF Proxy with a WS-Discovery Channel Factory
    /// <code>
    /// DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>(); <br />
    /// InArgument<List<Uri>> scopes = new InArgument<List<Uri>>(); <br />
    /// InArgument<Binding> binding = new InArgument<Binding>(); <br />
    /// Activity workflow = new WcfDiscoveryProxy<IMockService>() <br />
    /// &nbsp; { <br />
    /// &nbsp; &nbsp; Scopes = scopes <br />
    /// &nbsp; &nbsp; Binding = binding <br />
    /// &nbsp; &nbsp; Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>() <br />
    /// &nbsp; &nbsp; { <br />
    /// &nbsp; &nbsp; &nbsp; Argument = proxy, <br />
    /// &nbsp; &nbsp; &nbsp; Handler = new Sequence() <br />
    /// &nbsp; &nbsp; &nbsp; { <br />
    /// &nbsp; &nbsp; &nbsp; } <br />
    /// &nbsp; &nbsp; } <br />
    ///&nbsp;  } <br />
    /// </code>
    /// </summary>
    /// <typeparam name="T">Type of the Service Contract</typeparam>
    [ToolboxBitmapAttribute(typeof(EntryPoint), "Resources.WcfContractProxyToolbox.bmp")]
    [Designer(typeof(WcfContractProxyDesigner))]
    [ContentProperty("Body")]
    [Description("Build a WCF Proxy with a WS-Discovery Channel Factory for the service contract T")]
    public class WcfDiscoveryProxy<T> : AWcfProxyActivity<T>
        where T : class
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public void WcfConfigurationProxy()
        {
            Scopes = new InArgument<List<Uri>>();
        }

        /// <summary>
        /// Get Or set the Communication Binding
        /// <remarks>
        /// Required Argument
        /// </remarks>
        /// </summary>
        [Browsable(true)]
        [RequiredArgument]
        [Category("Proxy")]
        [Description("Get Or set the Communication Binding")]
        public InArgument<Binding> Binding { get; set; }

        /// <summary>
        /// Get or Set the list of Uri Scopes that will must match 
        /// </summary>
        [Browsable(true)]
        [Category("Discovery")]
        [Description("Get or Set the list of Uri Scopes that will must match")]
        public InArgument<List<Uri>> Scopes { get; set; }

        /// <summary>
        /// Get or set that the scopes are matched using the a defined method
        /// <remarks>
        /// Default Value is Prefix
        /// </remarks>
        /// </summary>
        [Browsable(true)]
        [Category("Discovery")]
        [Description("Get or set that the scopes are matched using the a  defined method")]
        public DiscoveryScopeMatch ScopeMatch { get; set; }

        /// <summary>
        /// Get or Set the maximum of results for a discovery
        /// </summary>
        [Browsable(true)]
        [Category("Discovery")]
        [DefaultValue(5)]
        [Description("Get or Set the maximum of results for a discovery")]
        public InArgument<int> MaxResults { get; set; }

        /// <summary>
        /// Get or Set the timeout for a discovery
        /// </summary>
        [Browsable(true)]
        [Category("Discovery")]
        [Description("Get or Set the timeout for a discovery")]
        public InArgument<TimeSpan> Timeout { get; set; }

        /// <summary>
        /// Get or Set the Discovery Provider
        /// <remarks>
        /// Default Value is an instance of UdpDiscovery Provider
        /// </remarks>
        /// </summary>
        [Browsable(true)]
        [Category("Misc")]
        [Description("Get or Set the Discovery Provider")]
        public InArgument<DiscoveryEndpointProvider> DiscoveryProvider { get; set; }

        /// <summary>
        /// Get the Service Endpoint
        /// </summary>
        /// <param name="context">The execution context in which the activity executes</param>
        /// <returns>Return the Service Endpoint</returns>
        protected override System.ServiceModel.Description.ServiceEndpoint GetServiceEndpoint(NativeActivityContext context)
        {
            int maxResults = MaxResults.Get(context);
            TimeSpan timeout = Timeout.Get(context);

            DynamicEndpoint discoveryEndpoint = new DynamicEndpoint(ContractDescription.GetContract(typeof(T)), Binding.Get(context));

            discoveryEndpoint.FindCriteria = new FindCriteria(typeof(T))
            {
                MaxResults = (maxResults > 0) ? maxResults : 5,
                Duration = (timeout != TimeSpan.Zero) ? timeout : new TimeSpan(0, 0, 30)
            };

            List<Uri> scopes = Scopes.Get(context);
            if (scopes == null)
                scopes = new List<Uri>();

            foreach (var scope in scopes)
                discoveryEndpoint.FindCriteria.Scopes.Add(scope);

            switch (ScopeMatch)
            {
                case DiscoveryScopeMatch.Prefix:
                    discoveryEndpoint.FindCriteria.ScopeMatchBy = FindCriteria.ScopeMatchByPrefix;
                    break;
                case DiscoveryScopeMatch.Exact:
                    discoveryEndpoint.FindCriteria.ScopeMatchBy = FindCriteria.ScopeMatchByExact;
                    break;
                case DiscoveryScopeMatch.Uuid:
                    discoveryEndpoint.FindCriteria.ScopeMatchBy = FindCriteria.ScopeMatchByUuid;
                    break;
                case DiscoveryScopeMatch.Ldap:
                    discoveryEndpoint.FindCriteria.ScopeMatchBy = FindCriteria.ScopeMatchByLdap;
                    break;
                case DiscoveryScopeMatch.None:
                    discoveryEndpoint.FindCriteria.ScopeMatchBy = FindCriteria.ScopeMatchByNone;
                    break;
                default:
                    discoveryEndpoint.FindCriteria.ScopeMatchBy = FindCriteria.ScopeMatchByPrefix;
                    break;
            }

            DiscoveryEndpointProvider discoveryProvider = DiscoveryProvider.Get(context);
            if(discoveryProvider != null)
                discoveryEndpoint.DiscoveryEndpointProvider = discoveryProvider;

            return discoveryEndpoint;
        }
    }
}
